using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using org.tmatesoft.svn.core;
using org.tmatesoft.svn.core.wc;

namespace Subsync.Core.Subversion
{
	/// <summary>
	/// Author: Hoang Duc
	/// </summary>
    class SVNInfo : CommandBase
    {
        //Initialise variables with default settings.
        private SVNURL url;
        private java.io.File path;
        private SVNRevision revision = SVNRevision.HEAD;
        private SVNRevision pegRevision = SVNRevision.PREVIOUS;
        private org.tmatesoft.svn.core.wc.SVNInfo info;
        private bool WC = false;
        public RevisionInfo revInfo { get; set; }
        private static Dictionary<string, RevisionInfo> all_path_files_info = new Dictionary<string, RevisionInfo>();

        public SVNInfo() { }

        /// <summary>
        /// WorkingCopy Constructor
        /// </summary>
        public SVNInfo(string path, string revision)
        {
            this.WC = true;
            this.path = new java.io.File(path);
            this.revision = SVNRevision.parse(revision);
        }

        /// <summary>
        /// Repository Constructor
        /// </summary>
        public SVNInfo(string url, string pegRevision, string revision)
        {
            this.WC = false;
            this.url = SVNURL.parseURIDecoded(url);
            this.revision = SVNRevision.parse(revision);
            this.pegRevision = SVNRevision.parse(pegRevision);
        }

        public static void SVNInfoAll (string path, string revision)
        {
            SVNInfo infoHandler;

            if (!Directory.Exists(path))
            {
                infoHandler = new SVNInfo(path, revision);
                infoHandler.Execute();
                SVNInfo.all_path_files_info.Add(path, infoHandler.revInfo);
                return;
            }

            string[] files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
            string[] dirs = Directory.GetDirectories(path, "*", SearchOption.AllDirectories);

            foreach (string f in files)
            {
                if (f.Contains(".svn"))
                    continue;
                infoHandler = new SVNInfo(f, revision);
                infoHandler.Execute();
                SVNInfo.all_path_files_info.Add(f, infoHandler.revInfo);
            }

            foreach (string d in dirs)
            {
                if (d.Contains(".svn"))
                    continue;
                infoHandler = new SVNInfo(d, revision);
                infoHandler.Execute();
                SVNInfo.all_path_files_info.Add(d, infoHandler.revInfo);
            }
        }

        public static string allFilesInfoToString()
        {
            string ret = "";
            foreach (KeyValuePair<string, RevisionInfo> f in SVNInfo.all_path_files_info)
                ret += f.Key.ToString() + "\n\n" + f.Value.ToString() + "\n\n";
            return ret;
        }

        public void handleInfo(Dictionary<string,List<object>> tokens)
        {
            if (tokens["info"].Count == 1)
            {                
                string filepath = (string)tokens["info"][0];
                this.WC = CheckPath(filepath);
                if (WC)
                {
                    this.path = new java.io.File(filepath);
                }
                else
                {
                    this.url = SVNURL.parseURIDecoded(filepath);
                    this.pegRevision = SVNRevision.parse("0");
                }
                this.revision = SVNRevision.parse("head");
            }
            else if (tokens["info"].Count == 2)
            {
                this.WC = true;
                string filepath = (string)tokens["info"][0];
                string revision = (string)tokens["info"][1];
                this.path = new java.io.File(filepath);
                this.revision = SVNRevision.parse(revision);
            }
            else if (tokens["info"].Count == 3)
            {
                this.WC = false;
                string url = (string)tokens["info"][0];
                string pegRevision = (string)tokens["info"][1];
                string revision = (string)tokens["info"][2];
                this.url = SVNURL.parseURIDecoded(url);
                this.pegRevision = SVNRevision.parse(pegRevision);
                this.revision = SVNRevision.parse(revision);
            }
            else
            {
                Console.WriteLine("Invalid arguments");
                return;
            }
        }

        public override void Execute()
        {
            Debug.WriteLine("SVNInfo Execution");

            //library setup
            Tools.SetupLibrary();

            //load up the clients
            SVNClientManager cm = SVNClientManager.newInstance();
            SVNWCClient wcc = cm.getWCClient();

            try
            {
                if (WC)
                {
                    this.info = wcc.doInfo(this.path, this.revision);
                    this.revInfo = new RevisionInfo(info.getAuthor(), info.getCommittedDate(), 
                        info.getCommittedRevision().getNumber(), this.path, 
                        new java.util.Date(this.path.lastModified()) , info.getRepositoryRootURL().toString(), 
                        info.getURL().toString(), info.getRevision().getNumber());
                }
                else
                {
                    this.info = wcc.doInfo(this.url, this.pegRevision, this.revision);
                    this.revInfo = new RevisionInfo(info.getAuthor(), info.getCommittedDate(), 
                        info.getCommittedRevision().getNumber(), this.url, 
                        null, info.getRepositoryRootURL().toString(), 
                        info.getURL().toString(), info.getRevision().getNumber());
                }
            }
            catch (SVNException e)
            {
                throw new SVNExecuteException(e.getMessage());
            }
        }

        public bool CheckPath(string inputPath)
        {
            // Checks if path is for repos access or WC access
            // Returns true for WC access
            Debug.WriteLine("SVN propget method to check if input path is repos access");
            List<string> repos_access = new List<string>();
            // List of Repos access URLs
            repos_access.Add("file://"); // Local repos
            repos_access.Add("http://");
            repos_access.Add("https://");
            repos_access.Add("svn://");
            repos_access.Add("svn+ssh://");

            foreach (string accessprefix in repos_access)
            {
                if (inputPath.StartsWith(accessprefix))
                    return false;
            }
            return true;
        }
    }
}
